package org.istt.web;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.struts2.ServletActionContext;
import org.istt.domain.FileStatus;
import org.istt.domain.ProcessStatus;
import org.istt.domain.Workflow;
import org.istt.domain.WorkflowProcess;
import org.istt.service.FileStatusManager;
import org.istt.service.ProcessStatusManager;
import org.istt.service.WorkflowManager;
import org.istt.web.helper.ExtendedPaginatedList;
import org.springframework.beans.factory.annotation.Autowired;

public class WorkflowAction extends BaseAction<WorkflowManager, Workflow, Long> {

	/**
	 * 
	 */
	private static final long serialVersionUID = -8003033308418700737L;
	private Workflow workflow;
	private List<ProcessStatus> lstSelectedProcessStatus;
	private List<ProcessStatus> lstProcessStatus;
	private ProcessStatusManager processStatusManager;
	private FileStatusManager fileStatusManager;
	private List<String> processStatus;
	private List<String> processTime;
	private List<String> fileStatus;
	private List<String> lineDept;
	private List<FileStatus> lstFileStatus;
	private Boolean used;
	private String stepName;
	private String wfName;
	
	
	public String search() {
		if (log.isDebugEnabled()) {
			log.debug("entering 'search workflow' method");
		}
		
		if(StringUtils.isNotEmpty(wfName)){
			ExtendedPaginatedList param = paginateListFactory.getPaginatedListFromRequest(ServletActionContext.getRequest());
			paginatedList = ((WorkflowManager)mgr).searchWf(wfName, param);
		}
		
		return SUCCESS;
	}
	private List<ProcessStatus> processes;
	private ProcessStatusManager processMgr;
	@Autowired
	public void setProcessMgr(ProcessStatusManager processMgr) {
		this.processMgr = processMgr;
	}
	
	public String searchProcess(){
		log.debug("Enter method 'searchProcess': "+stepName);
		if(StringUtils.isNotEmpty(stepName))  {
			setProcesses(this.processMgr.searchProcessStatus(stepName));
		}
		return SUCCESS;
	}
	
	public Boolean getUsed() {
		return used;
	}
	public void setUsed(Boolean used) {
		this.used = used;
	}
	public List<String> getFileStatus() {
		return fileStatus;
	}
	public void setFileStatus(List<String> fileStatus) {
		this.fileStatus = fileStatus;
	}
	
	public List<String> getLineDept() {
		return lineDept;
	}
	public void setLineDept(List<String> lineDept) {
		this.lineDept = lineDept;
	}
	//process time of a node
	public List<String> getProcessTime() {
		return processTime;
	}
	public void setProcessTime(List<String> processTime) {
		this.processTime = processTime;
	}
	//status of a node
	public List<String> getProcessStatus() {
		return processStatus;
	}
	public void setProcessStatus(List<String> processStatus) {
		this.processStatus = processStatus;
	}
	/*
	 * User choices
	 */
	public List<ProcessStatus> getLstSelectedProcessStatus() {
		return lstSelectedProcessStatus;
	}
	public void setLstSelectedProcessStatus(
			List<ProcessStatus> lstSelectedProcessStatus) {
		this.lstSelectedProcessStatus = lstSelectedProcessStatus;
	}
	
	/*
	 * System process status
	 */
	public List<ProcessStatus> getLstProcessStatus() {
		return lstProcessStatus;
	}
	public void setLstProcessStatus(List<ProcessStatus> lstProcessStatus) {
		this.lstProcessStatus = lstProcessStatus;
	}
	
	/*
	 * File status list
	 */
	public List<FileStatus> getLstFileStatus() {
		return lstFileStatus;
	}
	
	/*
	 * Manager
	 */
	@Autowired
	public void setProcessStatusManager(ProcessStatusManager processStatusManager) {
		this.processStatusManager = processStatusManager;
	}
	
	@Autowired
	public void setFileStatusManager(FileStatusManager fileStatusManager) {
		this.fileStatusManager = fileStatusManager;
	}
	
	/*
	 * Entity
	 */
	public Workflow getWorkflow() {
		return workflow;
	}
	public void setWorkflow(Workflow workflow) {
		this.workflow = workflow;
	}
	
	
	@SuppressWarnings("unchecked")
	@Override
	public String edit() throws Exception {
		String forward = super.edit();
		lstProcessStatus = processStatusManager.getList();
		lstFileStatus = fileStatusManager.getList();
		//forward the request to add new process
		if (entity.getId() == null) return forward;
		
		List<Object[]> items = ((WorkflowManager)mgr).getWfpByWfId(entity.getId());
		lstSelectedProcessStatus = new ArrayList<ProcessStatus>();
		
		for (Object[] item : items) {
			ProcessStatus ps = (ProcessStatus)item[0];
			
			/*boolean usedInFileMgr = (Integer)item[1] != 0;
			if (!BooleanUtils.isTrue(used) && usedInFileMgr) {
				used = true;
				addActionError(getText("workflow.error.in.used"));
			}*/
			ps.setUsed(false);
			ps.setWorkflowProcess((WorkflowProcess)item[2]);
			//ps.setLineDept(item[3] == null ? false : (Boolean)item[3]);
			//ps.setFileStatus((FileStatus)item[4]);
			
			lstSelectedProcessStatus.add(ps);
		}
		
		lstProcessStatus = (List<ProcessStatus>) CollectionUtils.subtract(lstProcessStatus, lstSelectedProcessStatus);
		
		workflow = entity;
		workflow.setDeletable(((WorkflowManager)mgr).isDeletable(entity.getId()));
		return forward;
	}
	
	@Override
	public Long getId() {
		if (getDelete() != null) {
			return workflow.getId();
		}
		return id;
	}
	
	@Override
	public Workflow getEntity() {
		if (workflow.getId() != null) {//edit workflow
			//Original items
			List<Object[]> items = ((WorkflowManager)mgr).getWfpByWfId(workflow.getId());
			
			//the list of process status that were used and unable to remove
			List<ProcessStatus> psOfWf = new ArrayList<ProcessStatus>();
			
			for (Object[] item : items) {
				ProcessStatus ps = (ProcessStatus)item[0];
				ps.setUsed((Integer)item[1] != 0);
				ps.setWorkflowProcess((WorkflowProcess)item[2]);
				
				if (!ps.isUsed()) {
					//remove all the status that were not exist in tbl_file_managerment
					((WorkflowManager)mgr).removeWorkflowProcess(workflow.getId(), ps.getId());
				} else {
					psOfWf.add(ps);
				}
			}
			
			//Selected items
			if (!CollectionUtils.isEmpty(processStatus)) {
				//add all the workflow_process to workflow
				for (int j = 0; j < processStatus.size(); j++) {
					String ps = processStatus.get(j);
					String pt = processTime.get(j);
					String fs = fileStatus.get(j);
					
					boolean found = false;
					for (ProcessStatus elm : psOfWf) {//with workflow process is unable to remove then update its properties
						if (elm.getId().equals(NumberUtils.toLong(ps))) {
							found = true;
							elm.getWorkflowProcess().setPosition(j+1);
							elm.getWorkflowProcess().setProcessTime(NumberUtils.toFloat(pt));
							elm.getWorkflowProcess().setLineDept(BooleanUtils.toBoolean(lineDept.get(j)));
							elm.getWorkflowProcess().setFileStatus(fileStatusManager.get(NumberUtils.toLong(fs)));
							// La buoc cuoi cung
							if(j+1 == psOfWf.size()){
								elm.getWorkflowProcess().setEndProcess(true);
							}
						}
					}
					
					if (found) continue;
					
					//add new workflow process to workflow
					WorkflowProcess wp = new WorkflowProcess();
					
					// La buoc cuoi cung
					if(j+1 == processStatus.size()){
						wp.setEndProcess(true);
					}
					
					wp.setPosition(j+1);
					wp.setProcessTime(NumberUtils.toFloat(pt));
					
					ProcessStatus processStatus = processStatusManager.get(NumberUtils.toLong(ps));
					wp.setProcessStatus(processStatus);
					
					FileStatus fileStatus = fileStatusManager.get(NumberUtils.toLong(fs));
					wp.setFileStatus(fileStatus);
					
					wp.setLineDept(BooleanUtils.toBoolean(lineDept.get(j)));
					wp.setWorkflow(workflow);
					
					
					
					workflow.addWorkflowProcess(wp);
				}
			}
			
		} else {//add new workflow
			int i = 0;
			if (!CollectionUtils.isEmpty(processStatus)) {
				for (int j = 0; j < processStatus.size(); j++) {
					String ps = processStatus.get(j);
					String pt = processTime.get(j);
					String fs = fileStatus.get(j);
					
					WorkflowProcess wp = new WorkflowProcess();
					
					// La buoc cuoi cung
					if(j+1 == processStatus.size()){
						wp.setEndProcess(true);
					}
					
					wp.setPosition(++i);
					wp.setProcessTime(NumberUtils.toFloat(pt));
					
					ProcessStatus processStatus = processStatusManager.get(NumberUtils.toLong(ps));
					wp.setProcessStatus(processStatus);
					
					FileStatus fileStatus = fileStatusManager.get(NumberUtils.toLong(fs));
					wp.setFileStatus(fileStatus);
					
					wp.setLineDept(BooleanUtils.toBoolean(lineDept.get(j)));
					wp.setWorkflow(workflow);
					
					
					
					workflow.addWorkflowProcess(wp);
				}
			}
		}		
		
		return workflow;
	}
	
	public boolean isValid() {
		return mgr.isUnique(new String[]{"name"}, new String[]{workflow.getName()}, workflow.getId());
	}
	
	public boolean isProcessTimeValid() {
		boolean isValid = true;
		if (!CollectionUtils.isEmpty(processTime)) {
			for (int i = 0; i < processTime.size(); i++) {
				if (NumberUtils.toFloat(processTime.get(i)) == 0.0f) {
					setProcessTimeInvalid(processTime.get(i));
					ProcessStatus ps = processStatusManager.get(NumberUtils.toLong(processStatus.get(i)));
					if (ps != null) {
						setProcessStatusNameInvalid(ps.getStatus());
					}
					isValid = false;
					break;
				}
			}
		} 
		return isValid;
	}
	
	
	private String processStatusNameInvalid = "";
	public String getProcessStatusNameInvalid() {
		return processStatusNameInvalid;
	}
	public void setProcessStatusNameInvalid(String processStatusNameInvalid) {
		this.processStatusNameInvalid = processStatusNameInvalid;
	}
	
	private String processTimeInvalid = "";
	public String getProcessTimeInvalid() {
		return processTimeInvalid;
	}
	public void setProcessTimeInvalid(String processTimeInvalid) {
		this.processTimeInvalid = processTimeInvalid;
	}
	
	public boolean isLineDeptValid() {
		boolean isValid = true;
		if (!CollectionUtils.isEmpty(lineDept) && !lineDept.containsAll(Arrays.asList(new String[]{"true"}))) {
			isValid = false;
		} 
		return isValid;
	}

	public void setWfName(String wfName) {
		this.wfName = wfName;
	}

	public String getWfName() {
		return wfName;
	}

	public void setStepName(String stepName) {
		this.stepName = stepName;
	}

	public String getStepName() {
		return stepName;
	}

	public void setProcesses(List<ProcessStatus> processes) {
		this.processes = processes;
	}

	public List<ProcessStatus> getProcesses() {
		return processes;
	}
}
